home *** CD-ROM | disk | FTP | other *** search
- Path: keats.ugrad.cs.ubc.ca!not-for-mail
- From: c2a192@ugrad.cs.ubc.ca (Kazimir Kylheku)
- Newsgroups: comp.lang.c
- Subject: Re: Best way to make a circle
- Date: 14 Feb 1996 14:23:09 -0800
- Organization: Computer Science, University of B.C., Vancouver, B.C., Canada
- Message-ID: <4ftncdINNr8p@keats.ugrad.cs.ubc.ca>
- References: <1996Feb8.043040.19301@lafn.org> <4fo6pt$39o@worf.qntm.com>
- NNTP-Posting-Host: keats.ugrad.cs.ubc.ca
-
- In article <4fo6pt$39o@worf.qntm.com>, <pb@netcom.com> wrote:
- >In <1996Feb8.043040.19301@lafn.org>, an234@lafn.org (Andres Lessing) writes:
- >>
- >>I am working on 3d Graphics quite succesfully as of now and am trying to
- >>put together a good Graphics library that is much faster than BGI drivers.
- >>I know that Sin and Cosine take to much time to calculate... so... which
- >>way should I do it?
- >>
- >First a little math...
- >Circle: x = sin(t)
- > y = cos(t) step t from 0..2pi
- >
- >difer: dx = +cos(t)/dt
- > dy = -sin(t)/dt
- >
- >subst: dx = +y/dt
- > dy = -x/dt
- >
- >let dt=1/64 and we have in c
- >
- > x += y/64;
- > y -= x/64; /* rad/64 or about 400 steps around */
- >
- >if we let m = 2pi/steps we get...
- >
- > x += m*y;
- > y -= m*x; /* 'tiz better to use the new x in this step */
- >
- >Using the above you step sin/cos using simple math. Properly scaled 16 bit values
- >aint bad. Test in spread sheet if you wish. Dont forget to reset to (x=0, y=1)
- >after one trip around or you get a growing circle.
-
- This is silly. Someone already posted the Bresenham algorithm which doesn't
- require any sines, cosines or multiplication, and approximates the circle
- better and better with greater resolution.
-
- The underpinnings behind are this. You represent the circle as an implicit
- equation:
-
- f(x,y) = x*x + y*y - r*r = 0
-
- You note that if you insert an arbitrary (x,y) pair into the functin f(x,y), if
- you insert the coordinates of a point that is outside of the circle, you get a
- negative result. Inserting a point that is inside the circle, you get a
- postive f(x,y). The circle is the locus of points for which f(x,y) = 0.
-
- With this in mind, you can start at the point (0, r) which you know is the
- point where the circle crosses the y axis and move left. You have a choice of
- two pixels. The one immediately to the right, (x+1,y), or the one to the right
- and below (x+1,y+1). You also know that your current value of f(x,y)---let us
- call it D---is zero (you are on the circle).
-
- To decide which pixel to step to, you look at D. If it is negative, you know
- you are out too far, so you choose the pixel (x+1,y+1), else you choose the one
- that is (x+1,y). You plot the pixel and update your (x,y) coordinates with
- simple increments as decided by the value of D.
-
- Now it turns out that you can update the value of D _precisely_ using a
- difference formula, without evaluating x*x + y*y - r*r, even though doing so
- would still be a lot better than using sines and cosine tables and such.
-
- In this case, you increasd only the x coordinate. So the amount to be added to
- D to correct it is:
-
- D_new - D_old = ((x+1)^2 + y*y - r*r) - (x*x + y*y - r*r)
- = x^2 + 2x + 1 - x^2
- = 2x + 1
-
- In other words, in the C language you do a " D += 2x + 1; ", which the
- compiler will quite likey strength-reduce into a shift and an add.
- There is no loss of accuracy unless x is so large that a shift left overflows.
- D never strays _too_ far from zero.
-
- Incidentally, the steps for updating in the case that you go to the other
- pixel are slightly different. You must compute the change in D for both the x
- and y increment. and you get something like
-
- D_new - D_old = 2x + 1 - 2y + 1
- = 2x - 2y + 2
- = 2(x - y + 1)
-
- So, the algorithm is:
-
- procedure circle(variable r)
- let x = 0
- let y = r
- let d = 0
-
- while (x <= y) # work over 45 degree slice
- plot (x,y) pixel
- plot all symmetric pixels (y,x), (-y,x), etc to get full circle
- if (D < 0) # we are out too far
- x = x + 1
- y = y + 1
- D = D + 2 * (x - y + 1) # optimizes, can be re-written
- else
- x = x + 1
- D = D + 2 * x - 1
- endif
- endwhile
-
-
- No sines, no cosines, no lookup tables, no fixed-point jumble. Lightning fast.
-
- Of course, this algorithm quantizes the circle. It is intended for raster
- devices. A floating point method involving stepping through a parametric
- equation might me appropriate for drawing a circle on plotter-like devices or
- vector displays.
-
- There are adaptations of this algorithm with anti-aliasing, etc.
-
- The method can be adapted for curves other than circles. I have done hyperbolas
- with it.
-
- The related method of forward differences for evalating cubic functions was
- used with Charles Babbage's difference engine. Today they use it to
- interpolate digital signals before reconstructing and sell it to you as
- "oversampling".
- --
-
-